using BSDS.Core.Data.Local;
using BSDS.Core.Data.Local.Jobs;
using BSDS.Core.Data.Local.Schema;
using BSDS.Core.Data.Local.Xml.Parsing;
using BSDS.Core.Data.Remote.Account;
using BSDS.Core.Data.Remote.Download;
using BSDS.Core.Data.Remote.Geocoding.Parsing;
using BSDS.Core.Data.Remote.Geocoding.Serialization;
using BSDS.Core.Data.Remote.Upload;
using BSDS.Core.Data.TemporaryFiles;
using BSDS.Core.Infrastructure;
using BSDS.Core.Infrastructure.Configuration;
using BSDS.Core.Infrastructure.Logging;
using BSDS.Core.Infrastructure.RemoteCommunication;
using BSDS.Core.Infrastructure.TransferProgress;
using BSDS.Core.Model.Services;
using BSDS.Core.Model.Services.Geocoding;
using BSDS.Core.Model.Services.Jobs;
using BSDS.Core.Model.Services.Uploading;
using BSDS.Core.Model.Services.Uploading.DataProviders;
using BSDS.Core.Services.BingRestApi;

namespace BSDS.Core.Intialization
{
    public class BsdsModule
    {
        public BsdsServicesLocator Build()
        {
            var loggerFactory = new LoggerFactory();
            var globalLogger = loggerFactory.Create("Global");
            var geocodingLogger = loggerFactory.Create("Geocoding");
            var transferLogger = loggerFactory.Create("Transfer");
            var accountLogger = loggerFactory.Create("Account");
            var uploadLogger = loggerFactory.Create("Upload");
            var jobLogger = loggerFactory.Create("Jobs");

            var configuration = new ConfigurationLoader().Load();

            var filenameProvider = new FilenameProvider(configuration.TempFolder);
            var tempFolderManager = new TempFolderManager(globalLogger, configuration.TempFolder, configuration.DeleteTempFolderOnExit);

            var formatRecognizer = new DataFormatRecognizer();
            var parserFactory = new LocalDataParserFactory(formatRecognizer);
            var serializerFactory = new LocalDataSerializerFactory();
            var dataRepository = new DataRepository(parserFactory, serializerFactory, filenameProvider, globalLogger);

            var streamFactory = new ReportingStreamFactory(transferLogger);
            var clientService = new ServiceClient(streamFactory);
            var dataProviderFactory = new DataProviderFactory(formatRecognizer);

            var jobRepository = new JobRepository(new GeocodeJobSerializer(globalLogger), new UploadJobSerializer(globalLogger), 
                new DownloadJobSerializer(globalLogger));

            var accountService = new AccountService(new AccountRequestSerializer(), clientService, new XmlSchemaSerializer(),
                                                accountLogger, configuration.BingKey);
            var uploadService = new UploadService(dataProviderFactory, dataRepository, jobRepository, clientService,
                                              new UploadResponseParser(), uploadLogger, configuration.BingKey);
            var downloadService = new DownloadService(accountService, clientService, jobRepository,
                                                      new DownloadResponseParser(), new XmlFormatParser(), 
                                                      globalLogger, configuration.BingKey);
            var locationsService = new BingRestLocationService(configuration.BingKey);
            var geoService = new GeocodingService(new GeoSerializer(filenameProvider), new GeoResponseParser(), 
                                              clientService, geocodingLogger, jobRepository, locationsService, configuration.BingKey);

            var jobService = new JobService(jobRepository, geoService, uploadService, downloadService, jobLogger);

            var mutexHolder = new NamedMutexHolder(globalLogger, configuration.RequireExclusiveFolderAccess);


            return new BsdsServicesLocator(tempFolderManager, mutexHolder, geoService, uploadService, accountService, 
                downloadService, dataRepository, jobRepository, jobService, formatRecognizer, loggerFactory);
        }
    }
}